#include "projectcreator.h"

ProjectCreator::ProjectCreator(){}

ProjectCreator::ProjectCreator(const QString &file, const QString &dir, const QDateTime &start,
                   const int &interval, const bool &included)
{
    expFile = file;
    this->included = included;
    this->interval = interval;
    this->start = start;
    this->dir = dir;
    imgSort = 0;
    expFileName = "";

    setupDatabase();
    setupTable();
    getFiles(dir.toStdString());
    processExpFile();
    updateFileName();
    createProj();
}

ProjectCreator::~ProjectCreator()
{
    closeDatabase();
    if(imgSort) delete imgSort;
    imgSort = 0;
}

/*
 *	Create sqlite database, and name the database name to be 
 *	current date time and hour
 *
 */
void ProjectCreator::setupDatabase()
{
    if(!QSqlDatabase::contains(QString("create")))
        db = QSqlDatabase::addDatabase("QSQLITE", "create");
    else
    {
        db = QSqlDatabase::database(QString("create"));
        if(!db.isOpen()) db.open();
    }

    QDateTime now = QDateTime::currentDateTime();
    QString name = "./data/";
    name = name.append(QString::number(now.date().month()) + "_");
    name = name.append(QString::number(now.date().day()) + "_");
    name = name.append(QString::number(now.time().hour()) + "_");
    name = name.append(QString::number(now.date().year()) + ".db");

	// Open database
    db.setDatabaseName(name);
    db.open();
}

/*
 *	Then create table in the database
 */
void ProjectCreator::setupTable()
{
    db.transaction();

    QSqlQuery query = QSqlQuery(db);
    QString stmt = QString("Create table experiment(id varchar(10), pdn varchar(10), exp varchar(10), family varchar(10), ");
    stmt = stmt.append("rep varchar(10), time varchar(10), germ varchar(10), gcum varchar(10), ");
    stmt = stmt.append("nseed varchar(10), fName varchar(100), primary key(id));");
    query.exec(stmt);
    db.commit();
}

/*
 *	Close database connection
 */
void ProjectCreator::closeDatabase()
{
    if(db.isOpen())
    {
        QSqlDatabase::database("create").close();
    }
}

/*
 *	Given a directory name, retrieve all the .jpg file from this folder
 */
bool ProjectCreator::getFiles(string dir)
{
    DIR *dp;
    struct dirent *dirp;

    if((dp = opendir(dir.c_str())) == NULL)
        return false;

    while ((dirp = readdir(dp)) != NULL)
    {
        string entity = dirp->d_name;
        QString fileName = QString::fromUtf8(entity.c_str());
        fileName = QString::fromUtf8(dir.c_str()).append("/" + fileName);
        QFileInfo info = QFileInfo(fileName);
        if(info.isFile() && fileName.contains(".JPG"))
            files.append(fileName);
    }

    closedir(dp);
    return true;
}

/*
 *	Process project info file which contains necessary experiment related information
 */
void ProjectCreator::processExpFile()
{
    QFile file(expFile);
    file.open(QIODevice::ReadOnly);
    QTextStream in(&file);
    // Assume first 3 lines contains project info.
    projInfo.append(in.readLine());
    projInfo.append(in.readLine());
    projInfo.append(in.readLine());

    while(!in.atEnd())
    {
        QString line = in.readLine();

        // Header lines of sas file to be skipped
        if(line.contains(",") || line.contains(";") || line.contains("pdn"))
        {
            continue;
        }
        else
        {
			// For each line that contain petri dish info
            QStringList list;
            list = line.simplified().split(" ");
            if(list.size() > 1) save(list);
        }
    }
    file.close();
}

/*
 *	Save each petri dish info to database
 */
void ProjectCreator::save(QStringList &list)
{
    QString id = list.at(0);
    QString pdn = list.at(1);
    QString exp = list.at(2);
    QString family = list.at(3);
    QString rep = list.at(4);
    QString time = list.at(5);
    QString germ = list.at(6);
    QString gcum = list.at(7);
    QString nseed = list.at(8);

    {
        db.transaction();
        QSqlQuery query = QSqlQuery(db);

        query.prepare("INSERT INTO experiment (id, pdn, exp, family, rep, time, germ, gcum, nseed) VALUES(?,?,?,?,?,?,?,?,?);");

        query.addBindValue(QVariant(id));
        query.addBindValue(QVariant(pdn));
        query.addBindValue(QVariant(exp));
        query.addBindValue(QVariant(family));
        query.addBindValue(QVariant(rep));
        query.addBindValue(QVariant(time));
        query.addBindValue(QVariant(germ));
        query.addBindValue(QVariant(gcum));
        query.addBindValue(QVariant(nseed));

        query.exec();
        db.commit();
    }

	// Save pdn and family info to corresponding list
    pdns.insert(pdn);
    families.insert(family);
}

/*
 *	Filter function that get time list based on selected pdn and append to 
 *	@result stringlist 
 */
void ProjectCreator::getTime(const QString &pdn, QStringList &result)
{
    {
        QSqlQuery query = QSqlQuery(db);

        query.prepare("select distinct(time) from experiment where pdn=? order by time;");
        query.addBindValue(QVariant(pdn));
        query.exec();
		// Loop through retrieved time list
		while(query.next())
        {
            result.append(query.value(0).toString());
        }
    }
}

void ProjectCreator::updateFileName()
{
    foreach (QString pdn , pdns)
    {
        // 'temp' is all image files associated with 'pdn'
        QStringList temp, time;

        for(int j = 0; j < files.size(); j++)
        {
            QString file = files.at(j);
            if(file.contains(pdn))
                temp.append(file);
        }

        // Sort files according to last modified date ascendingly
        delete imgSort;
        imgSort = new ImageSort(temp);
		// currently deprecated
		///////////////////////
        getTime(pdn, time);
        update(pdn, time, temp);
		///////////////////////
    }
}

void ProjectCreator::update(const QString &pdn, QStringList &time, QStringList &files)
{
    int s = 0;
    if(included) s = 1;

    for(int i = 0; i < time.size(); i++)
    {
        QString temp = time.at(i);
        int t = temp.toInt();

        if(s >= files.size())
            return;

        if(abs(t - QFileInfo(files.at(s)).lastModified().secsTo(start)/3600) <= 1)
            updateRow(pdn, temp, files.at(s));

        s++;
    }
}

void ProjectCreator::updateRow(const QString &pdn, const QString &time, const QString &file)
{
    QSqlQuery query = QSqlQuery(db);

    query.prepare("update experiment set fName=? where pdn=? and time=?;");
    query.addBindValue(QVariant(file));
    query.addBindValue(QVariant(pdn));
    query.addBindValue(QVariant(time));
    query.exec();
}

/*
 *	Create project file. Each project file is of type .sgf with current date time 
 *	and contains information about list of of image files, number of pdns, number 
 *	of families, location of image files as well as experiment imbibition time
 */
void ProjectCreator::createProj()
{
    QDateTime now = QDateTime::currentDateTime();
    expFileName = "./data/";
    expFileName = expFileName.append(QString::number(now.date().month()) + "_");
    expFileName = expFileName.append(QString::number(now.date().day()) + "_");
    expFileName = expFileName.append(QString::number(now.time().hour()) + "_");
    expFileName = expFileName.append(QString::number(now.date().year()) + ".sgf");

    ofstream out(expFileName.toStdString().c_str());
    if(out.is_open())
    {
        out << "<<<Database>>>" << endl;
        out << db.databaseName().toStdString().c_str() <<  endl;

        out << "<<<Experiment Header Information>>>"   << endl;
        out << projInfo.toStdString().c_str()  << endl;

        out << "<<<Image Files>>>" << endl;
        for(int i = 0; i < files.size(); i++)
            out << files.at(i).toStdString().c_str()  << endl;

        out << "<<<Number of pdn>>>"   << endl;
        out << pdns.size()   << endl;

        out << "<<<PDN's>>>"   << endl;
        foreach (QString pdn, pdns)
            out << pdn.toStdString().c_str()  << endl;

        out << "<<<Number of family>>>"   << endl;
        out << families.size()  << endl;

        out << "<<<Family's>>>"  << endl;
        foreach (QString family, families)
            out << family.toStdString().c_str()  << endl;

        out << "<<<Image Directory>>>" << endl;
        out << dir.toStdString().c_str() << endl;

        out << "<<<Experiment Imbibition Time>>>" << endl;
        out << this->start.toString().toStdString().c_str() << endl;

        out.close();
    }
    else
        qDebug() << "Can not create project file.";

}
